﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using SuePhotoManager_2_0.AppUtil;
using System.Text.RegularExpressions;

namespace SuePhotoManager_2_0.VLayer.Index
{
    public partial class FrmIndex : Form
    {
        public FrmIndex()
        {
            InitializeComponent();
            // 窗口设置
            this.StartPosition = FormStartPosition.CenterScreen;
            this.Text = AppConf.name + " " + AppConf.version;
            this.Icon = Reslib.rename64_ico;
            // 允许异步线程操作UI界面
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void FrmIndex_Load(object sender, EventArgs e)
        {
            // 按钮事件处理
            this.button_click_handler();
            change_event_handler();
        }

        /// <summary>
        /// 其他控件事件处理
        /// </summary>
        /// <remarks>2016-6-24</remarks>
        void change_event_handler()
        {
            chk_has_subdir.CheckedChanged += (object sender, EventArgs e) =>
            {
                panel_keep_struct.Visible = chk_has_subdir.Checked;
            };
            chk_resize.CheckedChanged += (object sender, EventArgs e) =>
            {
                panel_size.Visible = chk_resize.Checked;
            };
        }
        /// <summary>
        /// 按钮点击时间处理
        /// </summary>
        /// <remarks>2016-6-23 SoChishun Added.</remarks>
        void button_click_handler()
        {
            lnk_help.LinkClicked += (object sender, LinkLabelLinkClickedEventArgs e) =>
            {
                new Help.FrmHelp() { StartPosition = FormStartPosition.CenterScreen, Text = "帮助", Icon = Reslib.rename64_ico }.Show();
            };
            lnk_about.LinkClicked += (object sender, LinkLabelLinkClickedEventArgs e) =>
            {
                new About.FrmAbout() { StartPosition = FormStartPosition.CenterScreen, Text = "关于", Icon = Reslib.rename64_ico }.Show();
            };
            btn_open_dest.Click += (object sender, EventArgs e) =>
            {
                FolderBrowserDialog fbd = new FolderBrowserDialog() { ShowNewFolderButton = true };
                if (DialogResult.OK != fbd.ShowDialog())
                {
                    return;
                }
                tb_path_dest.Text = fbd.SelectedPath;
            };
            btn_open_src.Click += (object sender, EventArgs e) =>
            {
                FolderBrowserDialog fbd = new FolderBrowserDialog();
                if (DialogResult.OK != fbd.ShowDialog())
                {
                    return;
                }
                tb_path_src.Text = fbd.SelectedPath;
            };
            btn_go_src.Click += (object sender, EventArgs e) =>
            {
                string path = tb_path_src.Text.Trim();
                if (path.Length > 0 && Directory.Exists(path))
                {
                    System.Diagnostics.Process.Start(path);
                }
            };
            btn_go_dst.Click += (object sender, EventArgs e) =>
            {
                string path = tb_path_dest.Text.Trim();
                if (path.Length > 0 && Directory.Exists(path))
                {
                    System.Diagnostics.Process.Start(path);
                }
            };
            btn_cancel.Click += (object sender, EventArgs e) =>
            {
                logs.Add(new RenameLog()
                {
                    type = "Operate",
                    status = true,
                    message = "用户终止操作!",
                });
                save_log();
                Application.Exit();
            };
            btn_run.Click += (object sender, EventArgs e) =>
            {
                // 重新初始化变量
                filecount = 0;
                // 错误消息
                FormParams fparams;
                if (!get_form_param(out fparams))
                {
                    return;
                }
                // 文件总数
                filecount = count_dir_files(fparams.path_src, fparams.has_subdir);
                // 进度条初始化
                pbar_main.Minimum = 1;
                pbar_main.Maximum = filecount;
                pbar_main.Step = 1;
                pbar_main.Value = 1;
                lbl_counter.Text = string.Format("0/{0}", filecount);
                // 开始重命名(异步)
                Action<string, FormParams> act = do_rename;
                IAsyncResult ir = act.BeginInvoke(fparams.path_src, fparams, new AsyncCallback((IAsyncResult result) =>
                {
                    save_log();
                    if (pbar_main.Value == pbar_main.Maximum)
                    {
                        if (DialogResult.OK != MessageBox.Show("处理完成, 是否打开保存目录!", "处理结果", MessageBoxButtons.OKCancel))
                        {
                            return;
                        }
                        System.Diagnostics.Process.Start(fparams.path_dest);
                    }
                }), null);

            };
        }
        int filecount = 0;
        static List<RenameLog> logs = new List<RenameLog>();

        /// <summary>
        /// 获取表单参数
        /// </summary>
        /// <param name="fparams"></param>
        /// <returns></returns>
        /// <remarks>2016-7-5 SoChishun Added.</remarks>
        bool get_form_param(out FormParams fparams)
        {
            int outn;
            List<string> msgs = new List<string>();
            fparams = new FormParams()
            {
                path_src = tb_path_src.Text.Trim(),
                path_dest = tb_path_dest.Text.Trim(),
                name_format = tb_name_format.Text.Trim(),
                is_copy = chk_is_copy.Checked,
                keywords = tb_keywords.Text.Trim(),
                is_classify = chk_is_classify.Checked,
                ext_classes = tb_ext_classes.Lines,
                has_subdir = chk_has_subdir.Checked,
                keep_struct = chk_keep_struct.Checked,
                is_resize = chk_resize.Checked,
                img_height = int.TryParse(tb_height.Text, out outn) ? outn : 0,
                img_width = int.TryParse(tb_width.Text, out outn) ? outn : 0,
            };
            if (fparams.path_src.Length < 1)
            {
                msgs.Add("照片目录无效!");
            }
            else if (!Directory.Exists(fparams.path_src))
            {
                msgs.Add("照片目录不存在!");
            }
            if (fparams.path_dest.Length < 1)
            {
                msgs.Add("保存目录无效!");
            }
            else if (!Directory.Exists(fparams.path_dest))
            {
                msgs.Add("保存目录不存在!");
            }
            if (fparams.name_format.Length < 1)
            {
                msgs.Add("名称格式无效!");
            }
            if (fparams.is_resize && fparams.img_width < 1 && fparams.img_height < 1)
            {
                msgs.Add("照片尺寸无效!");
            }
            if (msgs.Count > 0)
            {
                MessageBox.Show(String.Join(Environment.NewLine, msgs), "错误");
                return false;
            }
            if (DialogResult.OK != MessageBox.Show("您确定要开始任务吗?", "提示", MessageBoxButtons.OKCancel))
            {
                return false;
            }

            // 保留源文件名的关键词
            fparams.keywordset = fparams.keywords.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
            // 扩展名归类
            string[] aline;
            fparams.ext_classesset = new Dictionary<string, string[]>();
            if (fparams.is_classify)
            {
                foreach (string line in fparams.ext_classes)
                {
                    if (line.Trim().Length < 1)
                    {
                        continue;
                    }
                    aline = line.Split(':');
                    if (aline.Length > 1)
                    {
                        fparams.ext_classesset[aline[0]] = aline[1].Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                    }
                }
            }
            return true;

        }

        /// <summary>
        /// 保持日志到文件
        /// </summary>
        /// <remarks>2016-7-5 SoChishun Added.</remarks>
        void save_log()
        {
            // 操作结束后写入日志
            IEnumerable<string> logText = logs.Select<RenameLog, string>(log =>
            {
                switch (log.type)
                {
                    case "Folder":
                        return string.Format("<folder status=\"{0}\"><message><![CDATA[{1}]]></message><src><![CDATA[{2}]]></src><dest><![CDATA[{3}]]></dest></folder>", log.status, log.message, log.path_src, log.path_desc);
                    case "Operate":
                        return string.Format("<operate status=\"{0}\"><message><![CDATA[{1}]]></message></operate>", log.status, log.message);
                    default:
                        return string.Format("<{5} id=\"{0}\" status=\"{1}\"><message><![CDATA[{2}]]></message><src><![CDATA[{3}]]></src><dest><![CDATA[{4}]]></dest></{5}>", log.i, log.status, log.message, log.path_src, log.path_desc, log.type.ToLower());
                }
            });
            string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><?xml-stylesheet type=\"text/css\" href=\"log_style.css\"?><root><head><title>照片重命名大师输出日志</title><date>Date：" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "</date><count>Count：" + filecount + "</count></head>" + String.Join(Environment.NewLine, logText) + "</root>";
            string logpath = string.Format("{0}\\log_{1}.xml", tb_path_dest.Text, DateTime.Now.ToString("MMdd_HHmm"));
            File.WriteAllText(logpath, xml);
            File.WriteAllText(tb_path_dest.Text + "\\log_style.css", "head{padding:5px 10px;border-bottom:solid  1px #CCC;display:block;font-size:12px;color:#666;}title{display:block;font-weight:bold;font-size:18px;margin-bottom:5px;}date,count{display:block;margin-top:3px;}folder,file,photo,operate{display:block;margin-top:5px;border-bottom:dotted 1px #CCC;padding:0 0 5px 10px;font-size:12px;line-height:18px;}[status='True'] message{color:#090;font-weight:bold;}photo[status='True'] message{color:#086;font-weight:bold;}[status='False'] message{color:#F00;font-weight:bold;}src,dest{display:block;color:#666;}");
            logs.Clear();
        }

        /// <summary>
        /// 执行重命名操作
        /// </summary>
        /// <param name="path_src"></param>
        /// <param name="fparams"></param>
        /// <remarks>2016-6-23</remarks>
        void do_rename(string path_src, FormParams fparams)
        {
            logs.Add(new RenameLog()
            {
                type = "Folder",
                status = true,
                path_src = path_src,
                path_desc = fparams.path_dest,
                message = string.Format("目录: 切换到[{0}]目录.", path_src),
            });
            DirectoryInfo di = new DirectoryInfo(path_src);
            FileInfo[] files = di.GetFiles();
            string destpath, destfile, thumbpath, name, ext;
            Regex reg = new Regex("\\[EXT\\]", RegexOptions.IgnoreCase);
            Regex regU = new Regex("\\[EXT:U\\]", RegexOptions.IgnoreCase);
            Regex regL = new Regex("\\[EXT:L\\]", RegexOptions.IgnoreCase);
            bool is_classify = fparams.is_classify && fparams.ext_classesset.Count > 0; // 是否扩展名归类
            bool is_rename; // 是否重命名
            foreach (FileInfo finfo in files)
            {
                is_rename = true;
                // 关键词判断是否需要重命名
                if (fparams.keywordset.Length > 0)
                {
                    foreach (string word in fparams.keywordset)
                    {
                        if ("*"==word || finfo.Name.Contains(word))
                        {
                            is_rename = false;
                            break;
                        }
                    }
                }
                if (is_rename) // 重命名
                {
                    ext = finfo.Extension.Substring(1);
                    if (is_classify) // 扩展名归类
                    {
                        foreach (string extclass in fparams.ext_classesset.Keys)
                        {
                            if (fparams.ext_classesset[extclass].Contains(ext))
                            {
                                ext = extclass;
                                break;
                            }
                        }
                    }
                    name = fparams.name_format;
                    if (name.Contains('[')) //  替换扩展名变量
                    {
                        name = reg.Replace(name, ext);
                        if (name.Contains(':'))
                        {
                            name = regL.Replace(name, ext.ToLower());
                            name = regU.Replace(name, ext.ToUpper());
                        }
                    }
                    // 取最小的时间
                    destfile = (DateTime.Compare(finfo.CreationTime, finfo.LastWriteTime) > 0 ? finfo.LastWriteTime : finfo.CreationTime).ToString(name);
                }
                else
                {
                    destfile = finfo.Name;
                }
                thumbpath = fparams.path_dest + "\\" + destfile + "_resize" + finfo.Extension; // 照片瘦身路径
                destpath = fparams.path_dest + "\\" + destfile + finfo.Extension;
                if (!File.Exists(destpath))
                {
                    if (fparams.is_copy)
                    {
                        finfo.CopyTo(destpath);
                    }
                    else
                    {
                        finfo.MoveTo(destpath);
                    }
                    // 照片瘦身
                    if (fparams.is_resize)
                    {
                        save_thumb(destpath, thumbpath, fparams.img_width, fparams.img_height);
                    }
                    logs.Add(new RenameLog()
                    {
                        i = pbar_main.Value,
                        type = "File",
                        status = true,
                        path_src = finfo.FullName,
                        path_desc = destpath,
                        message = string.Format("重命名({0}/{1}): 文件[{2}/{3}]成功.", pbar_main.Value, filecount, destfile, finfo.Name)
                    });
                }
                else
                {
                    logs.Add(new RenameLog()
                    {
                        i = pbar_main.Value,
                        type = "File",
                        status = false,
                        path_src = finfo.FullName,
                        path_desc = destpath,
                        message = string.Format("跳过重命名({0}/{1}): 文件[{2}/{3}]已存在.", pbar_main.Value, filecount, destfile, finfo.Name),
                    });
                }
                // 进度条设置
                pbar_main.Increment(1);
                // 统计消息设置
                lbl_counter.Text = string.Format("{0}/{1}", pbar_main.Value, filecount);
            }
            if (fparams.has_subdir)
            {
                DirectoryInfo[] dirs = di.GetDirectories();
                if (dirs.Length > 0)
                {
                    foreach (DirectoryInfo dinfo in dirs)
                    {
                        // 保存子目录结构
                        if (fparams.keep_struct)
                        {
                            fparams.path_dest += "\\" + dinfo.Name;
                            if (!Directory.Exists(fparams.path_dest))
                            {
                                Directory.CreateDirectory(fparams.path_dest);
                            }
                        }
                        do_rename(dinfo.FullName, fparams);
                    }
                }
            }

        }
        /// <summary>
        /// 获取文件数量
        /// </summary>
        /// <param name="path"></param>
        /// <param name="has_subdir"></param>
        /// <returns></returns>
        /// <remarks>2016-6-23</remarks>
        int count_dir_files(string path, bool has_subdir)
        {
            DirectoryInfo di = new DirectoryInfo(path);
            int counter = di.GetFiles().Length;
            if (has_subdir)
            {
                DirectoryInfo[] dirs = di.GetDirectories();
                if (dirs.Length > 0)
                {
                    foreach (DirectoryInfo dinfo in dirs)
                    {
                        counter += count_dir_files(dinfo.FullName, has_subdir);
                    }
                }
            }
            return counter;
        }
        /// <summary>
        /// 判断是否有效图片
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        /// <remarks>2016-6-24 SoChishun Added.</remarks>
        /// <see cref="http://bbs.csdn.net/topics/210072680"/>
        bool IsPicture(string filePath)
        {
            try
            {
                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    using (BinaryReader reader = new BinaryReader(fs))
                    {
                        string fileClass;
                        byte buffer;
                        byte[] b = new byte[2];
                        buffer = reader.ReadByte();
                        b[0] = buffer;
                        fileClass = buffer.ToString();
                        buffer = reader.ReadByte();
                        b[1] = buffer;
                        fileClass += buffer.ToString();

                        string[] imagecodes = new string[] { "255216", "7173", "6677", "13780" }; //255216是jpg;7173是gif;6677是BMP,13780是PNG;7790是exe,8297是rar 
                        return imagecodes.Contains(fileClass);
                    }
                }
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// 生成缩略图
        /// </summary>
        /// <param name="src">源图像文件的绝对路径</param>
        /// <param name="dest">生成的缩略图图像文件的绝对路径</param>
        /// <param name="thumbWidth">要生成的缩略图的宽度</param>
        /// <param name="thumbHeight">要生成的缩略图的高度</param>
        /// <remarks>2016-6-24 SoChishun Added.</remarks>
        /// <see cref="http://www.cnblogs.com/scgw/archive/2010/12/24/1915462.html"/>
        void save_thumb(string src, string dest, int thumbWidth, int thumbHeight)
        {
            if (!IsPicture(src))
            {
                return; // 不是有效图片
            }
            //利用Image对象装载源图像
            using (System.Drawing.Image image = System.Drawing.Image.FromFile(src))
            {
                //接着创建一个System.Drawing.Bitmap对象，并设置你希望的缩略图的宽度和高度。
                int srcWidth = image.Width;
                int srcHeight = image.Height;
                if (thumbWidth > 0 && thumbHeight < 1)
                {
                    // 宽度自定义,高度自适应
                    double size_scale = ((double)srcHeight / (double)srcWidth);
                    thumbHeight = (int)(size_scale * thumbWidth);
                }
                else if (thumbWidth < 1 && thumbHeight > 0)
                {
                    // 高度自定义,宽度自适应
                    double size_scale = ((double)srcWidth / (double)srcHeight);
                    srcWidth = (int)(size_scale * srcHeight);
                }
                using (Bitmap bmp = new Bitmap(thumbWidth, thumbHeight))
                {
                    try
                    {
                        //从Bitmap创建一个System.Drawing.Graphics对象，用来绘制高质量的缩小图。
                        System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(bmp);
                        //设置 System.Drawing.Graphics对象的SmoothingMode属性为HighQuality
                        gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                        //下面这个也设成高质量
                        gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                        //下面这个设成High
                        gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                        //把原始图像绘制成上面所设置宽高的缩小图
                        System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(0, 0, thumbWidth, thumbHeight);
                        gr.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel);
                        //保存图像，大功告成！
                        bmp.Save(dest);
                        logs.Add(new RenameLog()
                        {
                            i = pbar_main.Value,
                            type = "Photo",
                            status = true,
                            path_src = src,
                            path_desc = dest,
                            message = string.Format("照片瘦身({0}/{1}): 成功.", pbar_main.Value, filecount)
                        });
                    }
                    catch (Exception ex)
                    {
                        logs.Add(new RenameLog()
                        {
                            i = pbar_main.Value,
                            type = "Photo",
                            status = false,
                            path_src = src,
                            path_desc = dest,
                            message = string.Format("照片瘦身({0}/{1}): 失败[{2}].", pbar_main.Value, filecount, ex.Message)
                        });
                    }
                }
            }
        }

        /// <summary>
        /// 表单参数对象
        /// </summary>
        /// <remarks>2016-6-23</remarks>
        struct FormParams
        {
            public string path_src; // 照片源目录
            public string path_dest; // 输出目录
            public string name_format; // 名称格式
            public bool is_copy; // 是否保留源文件
            public string keywords; // 保持文件名关键词
            public bool is_classify; // 是否扩展名归类
            public string[] ext_classes; // 扩展名归类
            public bool has_subdir; // 是否包含子目录
            public bool keep_struct; // 是否保留子目录结构
            public bool is_resize; // 是否重设照片尺寸
            public int img_width; // 照片宽度
            public int img_height; // 照片高度
            public Dictionary<string, string[]> ext_classesset;
            public string[] keywordset;
        }
        /// <summary>
        /// 操作日志
        /// </summary>
        /// <remarks>2016-6-24</remarks>
        struct RenameLog
        {
            public int i;
            public string type;
            public string path_src;
            public string path_desc;
            public string message;
            public bool status;
        }
    }
}
